// tests.exe.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <vex.tests/msperf/tests.exe/Perf_test_runner_base.h>
#include <vex.tests/msperf/tests.exe/Perf_test_runner_ref_counting.h>
#include <vex.tests/msperf/tests.exe/Perf_test_runner_range_iteration.h>

namespace tests_exe {
    class VEX_ABSTRACT Perf_test_runner_aggregated 
        : public Perf_test_runner_base
        , public Iperf_test_runner_collector
    {
        typedef boost::intrusive_ptr<Iperf_test_runner> Iperf_test_runner_ip_t;
        typedef std::vector< Iperf_test_runner_ip_t > runner_cont_t;
        runner_cont_t m_runners;

        std::ostream& print_line(
            std::ostream& p_out, 
            Iperf_test_runner const* p_runner, 
            std::int64_t p_total_ticks) const
        {
            return p_out 
                << p_runner->name() 
                << " -> ticks: " 
                << p_runner->duration_in_ticks()
                << " -> " <<( double(p_runner->duration_in_ticks())/double(p_total_ticks)) * 100. << "%" << std::endl;
        }
    public:
        virtual bool move_front()
        {
            return true;
        }

        virtual bool put(Iperf_test_runner* p_runner)
        {
            try {
                if (p_runner) {
                    m_runners.push_back(p_runner);
                }
            } catch (...) {
                return false;
            }

            return false;
        }

        virtual const char* name() const
        {
            return "Perf_test_runner_aggregated";
        }

        virtual void run()
        {
            auto tp = boost::chrono::high_resolution_clock::now();
            for (auto const & r : m_runners) {
                if (r) {
                    r->run();
                }
            }
            set_duration_ticks((boost::chrono::high_resolution_clock::now() - tp).count());
        }

        void print_results(std::ostream& p_out) const
        {
            this->print_line(p_out, this, this->duration_in_ticks()); 
            runner_cont_t t_sorted(m_runners.begin(), m_runners.end());
            std::sort(t_sorted.begin(), t_sorted.end(), 
                [](boost::intrusive_ptr<Iperf_test_runner> const & p_l, 
                   boost::intrusive_ptr<Iperf_test_runner> const & p_r) -> bool {
                       return p_l->duration_in_ticks() < p_r->duration_in_ticks();
            });
            for (auto const & r : t_sorted) {
                if (r) {
                    this->print_line(p_out, r.get(), this->duration_in_ticks());
                }
            }
        }

        VEX_PROTECT_CONTRACT(Perf_test_runner_aggregated);
    };
}

int _tmain(int argc, _TCHAR* argv[])
{
    if (auto runners_collector = vex::core::make_intrusive_handle<tests_exe::Perf_test_runner_aggregated>()) {
        if (1 < argc) {
            for (int c = 1; c < argc; ++c) if (argv[c]) {
                if (std::wstring(argv[c]).compare(L"/ref_counting") == 0) {
                    tests_exe::ref_counting::append_your_runners(runners_collector.get());
                }
                if (std::wstring(argv[c]).compare(L"/range_iteration") == 0) {
                    tests_exe::range_iteration::append_your_runners(runners_collector.get());
                }
            }
        } else {
            tests_exe::ref_counting::append_your_runners(runners_collector.get());
            tests_exe::range_iteration::append_your_runners(runners_collector.get());
        }

        runners_collector->run();
        runners_collector->print_results(std::cout);
    }
}

